import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from nicegui import ui, app
import os
from plotly.subplots import make_subplots
import plotly.io as pio
import hashlib
import json
from pathlib import Path
import numpy as np
from scipy.interpolate import griddata
import statsmodels.api as sm
from datetime import datetime
from io import StringIO

# 设置全局主题和字体
pio.templates.default = "plotly_white"
pio.templates["plotly_white"].layout.font.update(family="Arial", size=12)

# 用户数据库文件和报告目录
USER_DB_FILE = 'users.json'
REPORT_DIR = 'reports'
os.makedirs(REPORT_DIR, exist_ok=True)


# 初始化用户数据库
def init_user_db():
    if not Path(USER_DB_FILE).exists():
        with open(USER_DB_FILE, 'w') as f:
            json.dump({}, f)


# 密码哈希处理
def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()


# 注册新用户
def register_user(username, password):
    with open(USER_DB_FILE, 'r') as f:
        users = json.load(f)

    if username in users:
        return False

    users[username] = {
        'password_hash': hash_password(password),
        'data_access': True
    }

    with open(USER_DB_FILE, 'w') as f:
        json.dump(users, f)

    return True


# 验证用户登录
def verify_user(username, password):
    with open(USER_DB_FILE, 'r') as f:
        users = json.load(f)

    if username not in users:
        return False

    return users[username]['password_hash'] == hash_password(password)


def load_data():
    try:
        df = pd.read_csv('pipe_thickness_loss_dataset.csv')
        ui.notify("数据加载成功！", type='positive')
        return df
    except Exception as e:
        ui.notify(f"数据加载失败: {str(e)}", type='negative')
        return None


def preprocess_data(df):
    if df.isnull().sum().sum() > 0:
        num_cols = df.select_dtypes(include=['float64', 'int64']).columns
        for col in num_cols:
            df[col].fillna(df[col].median(), inplace=True)
        cat_cols = df.select_dtypes(include=['object']).columns
        for col in cat_cols:
            df[col].fillna(df[col].mode()[0], inplace=True)

    num_cols = df.select_dtypes(include=['float64', 'int64']).columns
    for col in num_cols:
        Q1 = df[col].quantile(0.25)
        Q3 = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        df[col] = df[col].apply(lambda x: lower_bound if x < lower_bound else (upper_bound if x > upper_bound else x))

    return df


# 新增：生成统计分析报告
def generate_statistical_report(df):
    report = []

    # 基本统计信息
    report.append("=== 基本统计信息 ===")
    report.append(df.describe().to_string())

    # 相关性分析
    report.append("\n=== 相关性分析统计 ===")
    numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
    corr_matrix = df[numeric_cols].corr()
    report.append(corr_matrix.to_string())

    # 按材料分组统计
    if 'Material' in df.columns:
        report.append("\n=== 按材料分组的统计 ===")
        material_stats = df.groupby('Material')[numeric_cols].agg(['mean', 'median', 'std'])
        report.append(material_stats.to_string())

    # 按条件分组统计
    if 'Condition' in df.columns:
        report.append("\n=== 按条件分组的统计 ===")
        condition_stats = df.groupby('Condition')[numeric_cols].agg(['mean', 'median', 'std'])
        report.append(condition_stats.to_string())

    return "\n".join(report)


# 新增：执行回归分析
def perform_regression_analysis(df, x_col, y_col):
    X = df[x_col]
    y = df[y_col]
    X = sm.add_constant(X)  # 添加常数项

    model = sm.OLS(y, X).fit()

    # 创建回归结果图表
    fig = px.scatter(df, x=x_col, y=y_col, trendline="ols",
                     title=f'回归分析: {x_col} vs {y_col}',
                     labels={x_col: x_col, y_col: y_col})

    fig.update_layout(
        plot_bgcolor='white',
        paper_bgcolor='white',
        xaxis_title=x_col,
        yaxis_title=y_col
    )

    # 获取回归结果
    results = model.summary().as_text()

    return fig, results


# 新增：生成完整分析报告
def generate_full_report(df, analysis_type='basic'):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    report_filename = f"pipe_analysis_report_{timestamp}.txt"
    report_path = os.path.join(REPORT_DIR, report_filename)

    report_content = []
    report_content.append("=== 管道厚度损失分析报告 ===")
    report_content.append(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    report_content.append(f"数据集记录数: {len(df)}")

    # 基本统计信息
    report_content.append("\n=== 基本统计信息 ===")
    report_content.append(df.describe().to_string())

    # 相关性分析
    report_content.append("\n=== 相关性分析 ===")
    numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
    corr_matrix = df[numeric_cols].corr()
    report_content.append(corr_matrix.to_string())

    # 高级分析
    if analysis_type == 'advanced':
        report_content.append("\n=== 高级分析 ===")

        # 回归分析示例
        if 'Diameter_mm' in df.columns and 'Thickness_Loss_mm' in df.columns:
            X = df['Diameter_mm']
            y = df['Thickness_Loss_mm']
            X = sm.add_constant(X)
            model = sm.OLS(y, X).fit()
            report_content.append("\n回归分析: 直径 vs 厚度损失")
            report_content.append(model.summary().as_text())

    # 数据质量问题
    report_content.append("\n=== 数据质量检查 ===")
    missing_values = df.isnull().sum()
    report_content.append("缺失值统计:")
    report_content.append(missing_values[missing_values > 0].to_string())

    # 保存报告
    with open(report_path, 'w') as f:
        f.write("\n".join(report_content))

    return report_path


def create_3d_scatter(df, x_col, y_col, z_col, color_col):
    if not pd.api.types.is_numeric_dtype(df[color_col]):
        df[color_col + '_code'] = pd.factorize(df[color_col])[0]
        color_col = color_col + '_code'

    fig = px.scatter_3d(
        df,
        x=x_col,
        y=y_col,
        z=z_col,
        color=color_col,
        title=f'3D散点图: {x_col} vs {y_col} vs {z_col}',
        hover_data=['Pipe_ID', 'Material', 'Condition'],
        height=700,
        color_continuous_scale='Rainbow',
        range_color=[df[color_col].min(), df[color_col].max()]
    )

    fig.update_traces(
        marker=dict(
            size=8,
            opacity=0.9,
            line=dict(width=0),
            symbol='circle',
            sizemode='diameter'
        ),
        selector=dict(mode='markers')
    )

    fig.update_layout(
        scene=dict(
            xaxis=dict(title=x_col, range=[df[x_col].min() - 5, df[x_col].max() + 5]),
            yaxis=dict(title=y_col, range=[df[y_col].min() - 1, df[y_col].max() + 1]),
            zaxis=dict(title=z_col, range=[df[z_col].min() - 1, df[z_col].max() + 1]),
            camera=dict(
                eye=dict(x=1.2, y=1.2, z=0.6),
                up=dict(x=0, y=0, z=1)
            ),
            aspectmode='cube'
        ),
        coloraxis_colorbar=dict(
            title=color_col.replace('_code', '') if '_code' in color_col else color_col
        ),
        plot_bgcolor='white',
        paper_bgcolor='white'
    )

    return fig


def create_boxplot(df, x_col, y_col):
    fig = px.box(
        df,
        x=x_col,
        y=y_col,
        title=f'箱线图: {x_col} vs {y_col}',
        color=x_col,
        height=600,
        color_discrete_sequence=px.colors.qualitative.Pastel
    )

    fig.update_layout(
        xaxis_title=x_col,
        yaxis_title=y_col,
        boxmode='group',
        showlegend=True,
        plot_bgcolor='white',
        paper_bgcolor='white'
    )

    return fig


def create_heatmap(df, columns):
    corr = df[columns].corr()
    fig = px.imshow(
        corr,
        text_auto=True,
        aspect="auto",
        title='相关性热力图',
        height=600,
        color_continuous_scale='Blues'
    )

    fig.update_layout(
        xaxis_title="特征",
        yaxis_title="特征",
        coloraxis_colorbar=dict(title="相关系数"),
        plot_bgcolor='white',
        paper_bgcolor='white'
    )

    return fig


def create_histogram(df, col, color_col=None):
    fig = px.histogram(
        df,
        x=col,
        color=color_col,
        title=f'{col}分布直方图',
        marginal="box",
        height=600,
        nbins=30,
        color_discrete_sequence=px.colors.qualitative.Pastel
    )

    fig.update_layout(
        xaxis_title=col,
        yaxis_title="计数",
        bargap=0.1,
        plot_bgcolor='white',
        paper_bgcolor='white'
    )

    return fig


def create_scatter_matrix(df, dimensions, color_col):
    fig = px.scatter_matrix(
        df,
        dimensions=dimensions,
        color=color_col,
        title='散点矩阵图',
        height=800,
        color_discrete_sequence=px.colors.qualitative.Pastel
    )

    fig.update_traces(
        diagonal_visible=False,
        showupperhalf=False,
        marker=dict(size=3, opacity=0.6)
    )

    fig.update_layout(
        plot_bgcolor='white',
        paper_bgcolor='white'
    )
    return fig
def create_line_chart(df, x_col, y_col, color_col):
    # 数据预处理：按分组计算均值
    df_agg = df.groupby([x_col, color_col], as_index=False)[y_col].mean()

    # 高对比度色板
    material_colors = {
        'Copper': '#1f77b4',
        'Cast Iron': '#ff7f0e',
        'Aluminum': '#2ca02c',
        'Steel': '#d62728',
        'PVC': '#9467bd'
    }

    fig = px.line(
        df_agg,
        x=x_col,
        y=y_col,
        color=color_col,
        color_discrete_map=material_colors,
        title=f' 折线图{x_col} vs {y_col}',  # 通用化标题
        height=600
    )

    # 动态布局优化
    fig.update_layout(
        plot_bgcolor='white',
        paper_bgcolor='white',
        xaxis=dict(
            title=x_col,  # 动态显示X轴名称
            gridcolor='lightgray',
            showspikes=True,  # 显示悬停时的辅助线
            spikethickness=1
        ),
        yaxis=dict(
            title=y_col,  # 动态显示Y轴名称
            gridcolor='lightgray',
            showspikes=True
        ),
        hovermode="x unified",
        hoverlabel=dict(
            bgcolor="white",
            font_size=12
        )
    )

    # 为每条线添加独特样式
    for i, trace in enumerate(fig.data):
        trace.update(
            line=dict(width=2.5),
            opacity=0.9,
            mode="lines+markers",
            marker=dict(
                size=6,
                symbol=i + 1,  # 不同形状标记
                line=dict(width=1, color='DarkSlateGrey')
            ),
            hovertemplate=f"""
                {color_col}: {trace.name}<br>
                {x_col}: %{{x}}<br>
                {y_col}: %{{y}}<extra></extra>
            """  # 动态显示列名
        )

    return fig

def create_bar_chart(df, x_col, y_col, color_col):
    fig = px.bar(
        df,
        x=x_col,
        y=y_col,
        color=color_col,
        title=f'柱状图: {x_col} vs {y_col}',
        height=600
    )
    fig.update_layout(
        plot_bgcolor='white',
        paper_bgcolor='white'
    )
    return fig


def create_density_chart(df, col, color_col):
    fig = px.density_contour(
        df,
        x=col,
        color=color_col,
        title=f'{col}密度分布图',
        height=600
    )
    fig.update_layout(
        plot_bgcolor='white',
        paper_bgcolor='white'
    )
    return fig




def create_surface_chart(df, x_col, y_col, z_col, color_col=None):
    """创建高鲜艳度的3D曲面图，移除底部等高线"""
    try:
        # 数据预处理
        df = df.copy()
        for col in [x_col, y_col, z_col]:
            if not pd.api.types.is_numeric_dtype(df[col]):
                df[col] = pd.to_numeric(df[col], errors='coerce')

        # 移除无效数据
        df = df.dropna(subset=[x_col, y_col, z_col])

        # 创建更密集的网格数据（使曲面更平滑）
        x_unique = np.linspace(df[x_col].min(), df[x_col].max(), 80)
        y_unique = np.linspace(df[y_col].min(), df[y_col].max(), 80)
        xx, yy = np.meshgrid(x_unique, y_unique)

        # 使用griddata插值创建z值矩阵
        zz = griddata(
            (df[x_col], df[y_col]),
            df[z_col],
            (xx, yy),
            method='cubic'
        )

        # 自定义鲜艳的色彩方案（红黄紫粉蓝渐变）
        custom_colorscale = [
            [0.0, 'rgb(255,0,255)'], # 紫色
            [0.3, 'rgb(255,0,0)'],  # 红色
            [0.5, 'rgb(255,255,0)'],  # 黄色
            [0.75, 'rgb(255,192,203)'], # 粉色
            [1.0, 'rgb(0,0,255)']     # 蓝色
        ]

        # 创建高鲜艳度的曲面图 - 移除contours_z参数
        fig = go.Figure(data=[
            go.Surface(
                x=xx,
                y=yy,
                z=zz,
                colorscale=custom_colorscale,
                showscale=True,
                opacity=1.0,
                surfacecolor=zz,
                lighting=dict(
                    ambient=0.25,
                    diffuse=0.95,
                    specular=0.05,
                    roughness=0.25
                ),
                lightposition=dict(x=200, y=200, z=1500),
                colorbar=dict(
                    thickness=25,
                    len=0.8,
                    title=dict(
                        text=z_col,
                        font=dict(size=14, color='black')
                    ),
                    tickfont=dict(size=12, color='black')
                )
                # 已移除contours_z参数
            )
        ])

        # 设置高对比度的布局
        fig.update_layout(
            title=dict(
                text=f'<b>3D曲面图: {x_col} vs {y_col} vs {z_col}</b>',
                font=dict(size=18, color='darkblue'),
                x=0.5,
                xanchor='center'
            ),
            scene=dict(
                xaxis_title=f'<b>{x_col}</b>',
                yaxis_title=f'<b>{y_col}</b>',
                zaxis_title=f'<b>{z_col}</b>',
                camera=dict(
                    eye=dict(x=1.6, y=1.6, z=0.8),
                    up=dict(x=0, y=0, z=1),
                    center=dict(x=0, y=0, z=0)
                ),
                xaxis=dict(
                    backgroundcolor='rgba(255,255,255,0.1)',
                    gridcolor='rgba(100,100,100,0.5)',
                    showbackground=True,
                    title_font=dict(size=14, color='darkred')
                ),
                yaxis=dict(
                    backgroundcolor='rgba(255,255,255,0.1)',
                    gridcolor='rgba(100,100,100,0.5)',
                    showbackground=True,
                    title_font=dict(size=14, color='darkgreen')
                ),
                zaxis=dict(
                    backgroundcolor='rgba(255,255,255,0.1)',
                    gridcolor='rgba(100,100,100,0.5)',
                    showbackground=True,
                    title_font=dict(size=14, color='darkblue')
                ),
                aspectratio=dict(x=1, y=1, z=0.7),
                bgcolor='rgba(245,245,245,0.9)'
            ),
            height=850,
            margin=dict(l=60, r=60, b=60, t=90),
            plot_bgcolor='white',
            paper_bgcolor='white',
            font=dict(family="Arial", size=12, color="black")
        )

        return fig

    except Exception as e:
        print(f"创建曲面图时出错: {str(e)}")
        # 创建错误提示图
        fig = go.Figure()
        fig.update_layout(
            title="无法生成曲面图: 数据不符合要求",
            annotations=[
                dict(
                    text=f"错误: {str(e)}",
                    x=0.5,
                    y=0.5,
                    showarrow=False,
                    font=dict(size=16, color='red')
                )
            ],
            plot_bgcolor='white',
            paper_bgcolor='white'
        )
        return fig

def create_default_chart(df):
    fig = make_subplots(
        rows=1, cols=2,
        specs=[[{'type': 'scatter3d'}, {'type': 'xy'}]],
        subplot_titles=('3D散点图: 管道尺寸与厚度损失', '厚度损失分布直方图')
    )

    scatter = px.scatter_3d(
        df,
        x='Diameter_mm',
        y='Strength_MPa',
        z='Thickness_mm',
        color='Material'
    )

    for trace in scatter.data:
        fig.add_trace(trace, row=1, col=1)

    hist = px.histogram(
        df,
        x='Thickness_Loss_mm',
        color='Material',
        nbins=30
    )

    for trace in hist.data:
        fig.add_trace(trace, row=1, col=2)

    fig.update_layout(
        height=600,
        showlegend=True,
        margin=dict(l=50, r=50, b=50, t=50),
        plot_bgcolor='white',
        paper_bgcolor='white'
    )

    fig.update_scenes(
        row=1, col=1,
        xaxis_title='直径(mm)',
        yaxis_title='厚度(mm)',
        zaxis_title='厚度损失(mm)'
    )

    fig.update_xaxes(title_text='厚度损失(mm)', row=1, col=2)
    fig.update_yaxes(title_text='计数', row=1, col=2)

    return fig


# 定义所有页面路由
def init_pages():
    @ui.page('/')
    def home():
        ui.navigate.to('/login')

    @ui.page('/login')
    def login():
        with ui.column().classes('absolute-center items-center'):
            ui.label('登录').classes('text-2xl font-bold mb-4 text-blue-700')

            username = ui.input('用户名').props('outlined').classes('w-64 mb-2')
            password = ui.input('密码', password=True, password_toggle_button=True).props('outlined').classes(
                'w-64 mb-4')

            with ui.row():
                ui.button('登录', on_click=lambda: handle_login(username.value, password.value)).classes(
                    'bg-blue-500 text-white hover:bg-blue-600')
                ui.button('注册', on_click=lambda: ui.navigate.to('/register')).classes(
                    'bg-green-500 text-white hover:bg-green-600')

    @ui.page('/register')
    def register():
        with ui.column().classes('absolute-center items-center'):
            ui.label('注册新账户').classes('text-2xl font-bold mb-4 text-blue-700')

            username = ui.input('用户名').props('outlined').classes('w-64 mb-2')
            password = ui.input('密码', password=True, password_toggle_button=True).props('outlined').classes(
                'w-64 mb-2')
            confirm_password = ui.input('确认密码', password=True, password_toggle_button=True).props(
                'outlined').classes('w-64 mb-4')

            with ui.row():
                ui.button('注册', on_click=lambda: handle_register(
                    username.value,
                    password.value,
                    confirm_password.value
                )).classes('bg-green-500 text-white hover:bg-green-600')
                ui.button('返回登录', on_click=lambda: ui.navigate.to('/login')).classes(
                    'bg-blue-500 text-white hover:bg-blue-600')

    @ui.page('/analysis')
    def analysis():
        raw_df = load_data()
        if raw_df is None:
            ui.notify("无法加载数据，请检查数据文件", type='negative')
            ui.navigate.to('/login')

            def set_chart_type(chart_type_name):
                """更新当前选择的图表类型"""
                chart_type.text = f"当前选择: {chart_type_name}"
                ui.notify(f"已选择图表类型: {chart_type_name}")
            return

        df = preprocess_data(raw_df.copy())
        numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
        categorical_cols = df.select_dtypes(include=['object']).columns.tolist()

        with ui.header().classes('bg-blue-500 text-white p-4 shadow-md'):
            with ui.row().classes('w-full max-w-7xl mx-auto items-center'):
                ui.label('油气管道厚度损失多维度可视化系统').classes('text-2xl font-bold')
                ui.space()
                ui.button('退出', on_click=lambda: ui.navigate.to('/login')).classes(
                    'bg-red-500 text-white hover:bg-red-600')

        # 主容器 - 使用flex布局实现左右分栏
        with ui.row().classes('w-full max-w-7xl mx-auto p-4 gap-4 h-[calc(100vh-80px)]'):
            # 控制面板 - 左侧，宽度30%，添加滚动条
            with ui.column().classes(
                    'w-[30%] bg-gray-50 p-4 rounded-lg shadow-md overflow-y-auto border border-gray-200'):
                ui.label('控制面板').classes('text-xl font-bold mb-4 text-blue-700 border-b pb-2')

                # 添加数据集预览按钮
                with ui.card().classes('w-full mb-4 p-4 bg-white border border-gray-200'):
                    ui.button('预览数据集', on_click=lambda: show_data_preview()).classes(
                        'w-full bg-blue-500 text-white hover:bg-blue-600')

                # 新增：分析报告生成区域
                with ui.card().classes('w-full mb-4 p-4 bg-white border border-gray-200'):
                    ui.label('相关数据操作').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')

                    with ui.row().classes('w-full'):
                        ui.button('数据清洗', on_click=lambda: show_statistical_report()).classes(
                            'flex-grow bg-purple-500 text-white hover:bg-purple-600')

                    with ui.row().classes('w-full mt-2'):
                        ui.button('数据分析', on_click=lambda: generate_and_show_full_report()).classes(
                            'flex-grow bg-purple-700 text-white hover:bg-purple-800')

                    with ui.row().classes('w-full mt-2'):
                        ui.button('导出当前数据', on_click=lambda: export_current_data()).classes(
                            'flex-grow bg-green-600 text-white hover:bg-green-700')

                # 新增：回归分析区域
                with ui.card().classes('w-full mb-4 p-4 bg-white border border-gray-200'):
                    ui.label('回归分析').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')

                    regression_x = ui.select(
                        options=numeric_cols,
                        label='自变量(X)',
                        value='Diameter_mm' if 'Diameter_mm' in numeric_cols else numeric_cols[0]
                    ).props('outlined').classes('w-full mb-2')

                    regression_y = ui.select(
                        options=numeric_cols,
                        label='因变量(Y)',
                        value='Thickness_Loss_mm' if 'Thickness_Loss_mm' in numeric_cols else numeric_cols[1]
                    ).props('outlined').classes('w-full mb-2')

                    ui.button('执行回归分析', on_click=lambda: perform_regression(
                        regression_x.value, regression_y.value
                    )).classes('w-full bg-blue-600 text-white hover:bg-blue-700')

                    # 在analysis页面的控制面板部分，修改图表参数配置部分如下：

                    # 图表类型选择 - 改为按钮组形式
                    with ui.card().classes('w-full mb-4 p-4 bg-white border border-gray-200'):
                        ui.label('选择图表类型').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')

                        # 使用一个字典来存储当前选择的图表类型
                        chart_type = {'value': '组合视图'}  # 使用字典以便能够修改值

                        def set_chart_type(type_name):
                            """更新当前选择的图表类型"""
                            chart_type['value'] = type_name
                            chart_type_label.set_text(f"当前选择: {type_name}")
                            ui.notify(f"已选择图表类型: {type_name}")
                            update_chart()  # 选择类型后立即更新图表

                        with ui.button_group().classes('w-full'):
                            with ui.row().classes('w-full flex-wrap gap-1'):
                                ui.button('3D散点图', on_click=lambda: set_chart_type('3D散点图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('箱线图', on_click=lambda: set_chart_type('箱线图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('热力图', on_click=lambda: set_chart_type('热力图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('直方图', on_click=lambda: set_chart_type('直方图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                            with ui.row().classes('w-full flex-wrap gap-1'):
                                ui.button('散点矩阵图', on_click=lambda: set_chart_type('散点矩阵图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('组合视图', on_click=lambda: set_chart_type('组合视图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('折线图', on_click=lambda: set_chart_type('折线图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('柱状图', on_click=lambda: set_chart_type('柱状图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                            with ui.row().classes('w-full flex-wrap gap-1'):
                                ui.button('密度图', on_click=lambda: set_chart_type('密度图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')
                                ui.button('曲面图', on_click=lambda: set_chart_type('曲面图')) \
                                    .classes('flex-grow bg-blue-700 text-white hover:bg-blue-800')

                        # 当前选择的图表类型状态
                        chart_type_label = ui.label(f"当前选择: {chart_type['value']}").classes(
                            'text-sm mt-2 text-gray-600')

                    # 图表参数配置 - 使用单个卡片容器，内部根据图表类型动态显示
                    with ui.card().classes('w-full mb-4 p-4 bg-white border border-gray-200') as params_container:
                        # 3D散点图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '3D散点图'):
                            ui.label('3D散点图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            x_axis = ui.select(options=numeric_cols, label='X轴', value='Diameter_mm').props(
                                'outlined').classes('w-full mb-2')
                            y_axis = ui.select(options=numeric_cols, label='Y轴', value='Thickness_mm').props(
                                'outlined').classes('w-full mb-2')
                            z_axis = ui.select(options=numeric_cols, label='Z轴', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full mb-2')
                            color_by = ui.select(options=categorical_cols, label='颜色分类', value='Material').props(
                                'outlined').classes('w-full')

                        # 箱线图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '箱线图'):
                            ui.label('箱线图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            box_x = ui.select(options=categorical_cols, label='分类列', value='Material').props(
                                'outlined').classes('w-full mb-2')
                            box_y = ui.select(options=numeric_cols, label='数值列', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full')

                        # 热力图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '热力图'):
                            ui.label('热力图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            heatmap_cols = ui.select(
                                options=numeric_cols,
                                label='选择列',
                                value=numeric_cols[:5],
                                multiple=True
                            ).props('outlined').classes('w-full')

                        # 直方图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '直方图'):
                            ui.label('直方图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            hist_col = ui.select(options=numeric_cols, label='选择列', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full mb-2')
                            hist_color = ui.select(options=categorical_cols + [None], label='颜色分类(可选)',
                                                   value='Material').props('outlined').classes('w-full')

                        # 散点矩阵图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '散点矩阵图'):
                            ui.label('散点矩阵图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            scatter_matrix_cols = ui.select(
                                options=numeric_cols,
                                label='选择列',
                                value=numeric_cols[:4],
                                multiple=True
                            ).props('outlined').classes('w-full mb-2')
                            scatter_matrix_color = ui.select(options=categorical_cols, label='颜色分类',
                                                             value='Material').props('outlined').classes('w-full')

                        # 折线图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '折线图'):
                            ui.label('折线图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            line_x = ui.select(options=numeric_cols, label='X轴', value='Diameter_mm').props(
                                'outlined').classes('w-full mb-2')
                            line_y = ui.select(options=numeric_cols, label='Y轴', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full mb-2')
                            line_color = ui.select(options=categorical_cols, label='颜色分类', value='Material').props(
                                'outlined').classes('w-full')

                        # 柱状图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '柱状图'):
                            ui.label('柱状图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            bar_x = ui.select(options=categorical_cols, label='X轴', value='Material').props(
                                'outlined').classes('w-full mb-2')
                            bar_y = ui.select(options=numeric_cols, label='Y轴', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full mb-2')
                            bar_color = ui.select(options=categorical_cols, label='颜色分类', value='Condition').props(
                                'outlined').classes('w-full')

                        # 密度图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '密度图'):
                            ui.label('密度图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            density_col = ui.select(options=numeric_cols, label='选择列',
                                                    value='Thickness_Loss_mm').props('outlined').classes('w-full mb-2')
                            density_color = ui.select(options=categorical_cols, label='颜色分类',
                                                      value='Material').props('outlined').classes('w-full')

                        # 曲面图参数
                        with ui.column().bind_visibility_from(chart_type, 'value', lambda val: val == '曲面图'):
                            ui.label('曲面图参数').classes('text-lg font-semibold mb-2 text-gray-700 border-b pb-2')
                            surface_x = ui.select(options=numeric_cols, label='X轴', value='Diameter_mm').props(
                                'outlined').classes('w-full mb-2')
                            surface_y = ui.select(options=numeric_cols, label='Y轴', value='Thickness_mm').props(
                                'outlined').classes('w-full mb-2')
                            surface_z = ui.select(options=numeric_cols, label='Z轴', value='Thickness_Loss_mm').props(
                                'outlined').classes('w-full mb-2')
                            surface_color = ui.select(options=categorical_cols, label='颜色分类',
                                                      value='Material').props('outlined').classes('w-full')

                    # 操作按钮
                    with ui.row().classes('w-full justify-between mt-4'):
                        ui.button('更新图表', on_click=lambda: update_chart()).classes(
                            'bg-blue-500 text-white hover:bg-blue-600 flex-grow')

                    # 数据统计信息
                    with ui.expansion('数据统计信息', icon='info').classes(
                            'w-full mt-4 bg-white border border-gray-200'):
                        with ui.card().classes('w-full p-4'):
                            ui.label(f"总记录数: {len(df)}").classes('text-sm')
                            ui.label(f"数值列: {', '.join(numeric_cols)}").classes('text-sm')
                            ui.label(f"分类列: {', '.join(categorical_cols)}").classes('text-sm')

                    # 数据筛选
                    with ui.expansion('数据筛选', icon='filter_alt').classes(
                            'w-full mt-4 bg-white border border-gray-200'):
                        with ui.card().classes('w-full p-4'):
                            condition_select = ui.select(
                                options=['全部'] + df['Condition'].unique().tolist(),
                                label='管道状态',
                                value='全部'
                            ).props('outlined').classes('w-full mb-2')
                            material_select = ui.select(
                                options=['全部'] + df['Material'].unique().tolist(),
                                label='材料类型',
                                value='全部'
                            ).props('outlined').classes('w-full mb-2')
                            ui.button('应用筛选', on_click=lambda: apply_filters()).classes(
                                'w-full bg-green-500 text-white hover:bg-green-600')

            # 可视化结果 - 右侧，宽度70%，背景改为白色
            with ui.column().classes('flex-1 bg-white p-4 rounded-lg shadow-md border border-gray-200 min-h-[600px]'):
                ui.label('分析结果').classes('text-xl font-bold mb-4 text-blue-700 border-b pb-2')

                # 创建默认图表容器
                plot_container = ui.column().classes('w-full h-full')

                # 创建数据预览容器，初始隐藏
                data_preview_container = ui.column().classes('w-full h-full').style('display: none')

                # 新增：报告显示容器，初始隐藏
                report_container = ui.column().classes('w-full h-full').style('display: none')

                # 初始化默认图表
                default_fig = create_default_chart(df)
                plot_container.clear()
                with plot_container:
                    ui.plotly(default_fig).classes('w-full h-full')

        # 新增：显示统计报告
        def show_statistical_report():
            report_content = generate_statistical_report(df)

            plot_container.style('display: none')
            data_preview_container.style('display: none')
            report_container.style('display: block')

            report_container.clear()
            with report_container:
                ui.label('数据清洗统计报告').classes('text-lg font-bold mb-2')
                ui.code(report_content).classes('w-full h-[600px] overflow-auto')
                ui.button('返回图表视图', on_click=lambda: show_chart_view()).classes(
                    'mt-4 bg-blue-500 text-white hover:bg-blue-600')

        # 新增：生成并显示完整报告
        def generate_and_show_full_report():
            report_path = generate_full_report(df, analysis_type='advanced')

            with open(report_path, 'r') as f:
                report_content = f.read()

            plot_container.style('display: none')
            data_preview_container.style('display: none')
            report_container.style('display: block')

            report_container.clear()
            with report_container:
                ui.label('完整数据分析报告').classes('text-lg font-bold mb-2')
                ui.code(report_content).classes('w-full h-[600px] overflow-auto')

                with ui.row().classes('w-full mt-2'):
                    ui.button('返回图表视图', on_click=lambda: show_chart_view()).classes(
                        'bg-blue-500 text-white hover:bg-blue-600')
                    ui.button('下载报告', on_click=lambda: download_report(report_path)).classes(
                        'bg-green-500 text-white hover:bg-green-600')

        # 新增：下载报告
        def download_report(report_path):
            with open(report_path, 'rb') as f:
                content = f.read()

            filename = os.path.basename(report_path)
            ui.download(content, filename)
            ui.notify(f"报告已下载: {filename}", type='positive')

        # 新增：执行回归分析
        def perform_regression(x_col, y_col):
            fig, results = perform_regression_analysis(df, x_col, y_col)

            plot_container.style('display: none')
            data_preview_container.style('display: none')
            report_container.style('display: block')

            report_container.clear()
            with report_container:
                ui.label(f'回归分析结果: {x_col} vs {y_col}').classes('text-lg font-bold mb-2')

                with ui.row().classes('w-full'):
                    with ui.column().classes('w-1/2 pr-2'):
                        ui.plotly(fig).classes('w-full h-[400px]')

                    with ui.column().classes('w-1/2 pl-2'):
                        ui.code(results).classes('w-full h-[400px] overflow-auto')

                ui.button('返回图表视图', on_click=lambda: show_chart_view()).classes(
                    'mt-4 bg-blue-500 text-white hover:bg-blue-600')

        # 新增：导出当前数据
        def export_current_data():
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"pipe_data_export_{timestamp}.csv"

            # 使用StringIO创建内存中的CSV文件
            output = StringIO()
            df.to_csv(output, index=False)
            csv_content = output.getvalue()
            output.close()

            ui.download(csv_content.encode(), filename)
            ui.notify(f"数据已导出: {filename}", type='positive')

        # 保留原有的视图切换和更新函数
        def show_data_preview():
            # 显示数据预览，隐藏图表
            plot_container.style('display: none')
            data_preview_container.style('display: block')

            # 清空并重新填充数据预览容器
            data_preview_container.clear()
            with data_preview_container:
                ui.label('数据集预览').classes('text-lg font-bold mb-2')
                # 创建表格并设置样式
                table = ui.table.from_pandas(df.head(1000)).classes('w-full max-h-[600px]')
                table.add_slot('body-cell', '''
                    <q-td :props="props" style="padding: 4px 8px;">
                        {{ props.value }}
                    </q-td>
                ''')
                # 添加返回按钮
                ui.button('返回图表视图', on_click=lambda: show_chart_view()).classes(
                    'mt-4 bg-blue-500 text-white hover:bg-blue-600')

        def show_chart_view():
            # 显示图表，隐藏数据预览和报告
            data_preview_container.style('display: none')
            report_container.style('display: none')
            plot_container.style('display: block')

        def update_chart():
            nonlocal df
            current_chart = chart_type['value']  # 直接从字典获取当前选择

            if current_chart == '3D散点图':
                fig = create_3d_scatter(
                    df,
                    x_axis.value,
                    y_axis.value,
                    z_axis.value,
                    color_by.value
                )
            elif current_chart == '箱线图':
                fig = create_boxplot(
                    df,
                    box_x.value,
                    box_y.value
                )
            elif current_chart == '热力图':
                fig = create_heatmap(
                    df,
                    heatmap_cols.value
                )
            elif current_chart == '直方图':
                fig = create_histogram(
                    df,
                    hist_col.value,
                    hist_color.value if hist_color.value != 'None' else None
                )
            elif current_chart == '散点矩阵图':
                fig = create_scatter_matrix(
                    df,
                    scatter_matrix_cols.value,
                    scatter_matrix_color.value
                )
            elif current_chart == '组合视图':
                fig = create_default_chart(df)
            elif current_chart == '折线图':
                fig = create_line_chart(
                    df,
                    line_x.value,
                    line_y.value,
                    line_color.value
                )
            elif current_chart == '柱状图':
                fig = create_bar_chart(
                    df,
                    bar_x.value,
                    bar_y.value,
                    bar_color.value
                )
            elif current_chart == '密度图':
                fig = create_density_chart(
                    df,
                    density_col.value,
                    density_color.value
                )
            elif current_chart == '曲面图':
                fig = create_surface_chart(
                    df,
                    surface_x.value,
                    surface_y.value,
                    surface_z.value,
                    surface_color.value
                )

            # 更新图表视图
            plot_container.clear()
            with plot_container:
                ui.plotly(fig).classes('w-full h-full')

            # 确保显示的是图表视图
            show_chart_view()

        def apply_filters():
            nonlocal df
            filtered_df = raw_df.copy()
            if condition_select.value != '全部':
                filtered_df = filtered_df[filtered_df['Condition'] == condition_select.value]
            if material_select.value != '全部':
                filtered_df = filtered_df[filtered_df['Material'] == material_select.value]
            df = preprocess_data(filtered_df)
            ui.notify(f"筛选后数据: {len(df)}条记录", type='positive')
            update_chart()

        # 初始化视图
        update_chart()


def handle_login(username, password):
    if not username or not password:
        ui.notify('请输入用户名和密码', type='negative')
        return

    if verify_user(username, password):
        ui.notify('登录成功!', type='positive')
        ui.navigate.to('/analysis')
    else:
        ui.notify('用户名或密码错误', type='negative')


def handle_register(username, password, confirm_password):
    if not username or not password:
        ui.notify('请输入用户名和密码', type='negative')
        return

    if password != confirm_password:
        ui.notify('两次输入的密码不一致', type='negative')
        return

    if register_user(username, password):
        ui.notify('注册成功! 请登录', type='positive')
        ui.navigate.to('/login')
    else:
        ui.notify('用户名已存在', type='negative')


if __name__ in ["__main__", "__mp_main__"]:
    init_user_db()

    if not os.path.exists('pipe_thickness_loss_dataset.csv'):
        ui.notify("错误: 数据集文件 'pipe_thickness_loss_dataset.csv' 不存在!", type='negative')

    # 初始化所有页面
    init_pages()

    # 默认跳转到登录页面
    ui.navigate.to('/login')

    ui.run(title='油气管道厚度损失多维度可视化系统', port=8080, reload=False)